Hihocode 1492 Parentheses Sequence(dp)

题意:
$给定一个长度为N\le 10^3的括号串,可以插入括号$
$问变成合法的括号串的最短插入次数,和方法数$

分析:
$首先回顾一下如何表示一个合法的括号串$
$令’(‘=1,’)’=-1,那么需要前缀和\ge 0,且和=0$
$那么显然我们有一个三方的dp$
$f[i][j][k]:=1\sim i,插入了j个括号,sum=k的方法数$
$再开个bool表示一下状态存不存在即可$
$这样就可以找到最少多少个,以及相应的方案数了$

$蓝儿三方是不能过的,思考一下,这其实是一个背包问题$
$背包的是sum,所以其实我们看成是一个图的问题,即n\times sum个节点的图$
$那么插入的括号的个数自然变成了最短路,方法数自然变成了最短路方案数$
$然后dp就变成了f[i][k]:=1\sim i,sum=k的最少插入括号数和方法数$
$最后减去原来的括号个数即可$
$这个背包化图的思路可以做一下上次CF 407的C:$题目链接

代码:

//
//  Created by TaoSama on 2017-04-04
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cerr << #x << " = " << x << "  "
#define prln(x) cerr << #x << " = " << x << endl
const int N = 1e3 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

int n;
char s[N];
int f[N][N], g[N][N];

void add(int& x, int y) {
    if((x += y) >= MOD) x -= MOD;
}

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    scanf("%s", s + 1);
    n = strlen(s + 1);

    queue<pair<int, int>> q;
    memset(f, -1, sizeof f);
    f[0][0] = 0, g[0][0] = 1;
    q.push({0, 0});
    while(q.size()) {
        int i, j; tie(i, j) = q.front(); q.pop();
        for(int k = -1; k <= 1; k += 2) {
            char c = k == 1 ? '(' : ')';
            int ni = min(n, i + (s[i + 1] == c));
            int nj = j + k;
            if(nj >= 0 && nj <= n) {
                if(f[ni][nj] == -1) {
                    f[ni][nj] = f[i][j] + 1;
                    g[ni][nj] = g[i][j];
                    q.push({ni, nj});
                } else if(f[ni][nj] == f[i][j] + 1) {
                    add(g[ni][nj], g[i][j]);
                }
            }
        }
    }
    printf("%d %d\n", f[n][0] - n, g[n][0]);

    return 0;
}